/* ==================================================================   
 * Created [2009-4-27 下午11:32:55] by Jon.King 
 * ==================================================================  
 * TSS 
 * ================================================================== 
 * mailTo:jinpujun@hotmail.com
 * Copyright (c) Jon.King, 2009-2012 
 * ================================================================== 
*/

package com.jinhe.tss.component.recycle;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.aopalliance.intercept.MethodInvocation;

import com.jinhe.tss.component.recycle.entity.Recycle;
import com.jinhe.tss.component.support.persistence.entityaop.IDecodable;
import com.jinhe.tss.component.support.persistence.entityaop.MatchByDaoMethodNameInterceptor;
import com.jinhe.tss.core.persistence.IDao;
import com.jinhe.tss.core.persistence.IEntity;
import com.jinhe.tss.core.sso.Environment;
import com.thoughtworks.xstream.XStream;

/**
 * <p> RecycleInterceptor.java </p>
 * <p>
 * 回收拦截器。
 * 一般拦截应用中Dao对象，如果调用的dao方法名中含delete、remove等字样，且第一个参数为Recycleable接口实例
 * 且当前线程的回收拦截器没有被关闭，则执行回收站操作。
 * 
 * 本拦截器需要配置在拦截器列的最后一个，否则其后的拦截器不会被执行。
 * </p>
 */
public class RecycleInterceptor extends MatchByDaoMethodNameInterceptor {

    /* 控制当前线程中，回收站的拦截功能是否打开。（用以放行物理删除等操作） */
    public static ThreadLocal<String> switchTL = new ThreadLocal<String>();
    
    @SuppressWarnings("unchecked")
    public Object invoke(MethodInvocation invocation) throws Throwable {
        String methodName = invocation.getMethod().getName();
		if (DELETE == judgeManipulateKind(methodName) && !SWITCH_CLOSE_TAG.equals(switchTL.get())) {
			Object[] args = invocation.getArguments();
			if( args[0] instanceof Recycleable && invocation.getThis() instanceof IDao ){
			    IDao<IEntity> dao = (IDao<IEntity>) invocation.getThis();
			    Recycleable deletedEntity = (Recycleable)args[0];
				RecycleResource source = RecycleConfig.getRecycleSource(deletedEntity.getClass().getName());

		        //判断该类型的数据是否要进行回收操作
		        if (source.getToRecycle() == 1) {
		            //创建垃圾回收记录
		            Recycle recycle = createRecycleInfo(deletedEntity, source, invocation);
		            dao.create(recycle); 

		            //执行逻辑删除
		            logicDelete(deletedEntity, source, recycle, dao);
		            
		            return deletedEntity;
		        } 
			}
		}
		return invocation.proceed();
	}
    
    /**
     * 创建一条垃圾回收信息
     * @param deletedEntity
     * @param source
     * @param invocation
     * @return
     */
     Recycle createRecycleInfo(Recycleable deletedEntity, RecycleResource source, MethodInvocation invocation){
        Recycle recycle = new Recycle();
        recycle.setNodeId(deletedEntity.getId());
        recycle.setNodeName(deletedEntity.getName());
        recycle.setTypeId(source.getId());
        recycle.setTypeName(source.getName());
        recycle.setEntityClass(deletedEntity.getClass().getName());
        
        recycle.setBeanId(source.getBeanId()); //被拦截的Dao对象ID
        recycle.setMethodName(invocation.getMethod().getName()); //被拦截的方法名称
        
        List<Object> params = new ArrayList<Object>();
        params.add(invocation.getArguments());
        params.add(invocation.getMethod().getParameterTypes());
        recycle.setParams(new XStream().toXML(params)); //被拦截方法的参数和参数类型
        
        recycle.setUserId(Environment.getOperatorId());
        recycle.setUserName(Environment.getOperatorName());
        recycle.setDeleteDate(new Date());
        
        return recycle;
    }

    /**
     * 逻辑删除
     * 
     * @param deletedEntity
     * @param resource
     * @param recycle
     * @param template
     */
    private void logicDelete(Recycleable deletedEntity, RecycleResource resource, Recycle recycle, IDao<IEntity> dao) {
        /* primary(update) */
        deletedEntity.setRecycleId(recycle.getId());  //设置删除实体对应回收站的记录
        deletedEntity.setDeleted(Recycle.TRUE);       //打上删除标记
        dao.update((IEntity) deletedEntity);

        //如果被删除实体是多层结构，则删除其子节点
        if ( resource.isMultiLayer() ) {
            logicDeleteChild(deletedEntity, dao);
        }
    }

    /**
     * 逻辑删除子节点
     * @param deletedEntity
     * @param template
     */
    private void logicDeleteChild(Recycleable deletedEntity, IDao<IEntity> dao) {
        IDecodable node = (IDecodable) deletedEntity; //层次结构一定继承IDecodable接口
        String hqlGetchild = "from " + deletedEntity.getClass().getName() + " where decode like ? ";
        
        List<?> list = dao.getEntities(hqlGetchild, node.getDecode() + "%");
        for (Iterator<?> it = list.iterator(); it.hasNext();) {
            Recycleable child = (Recycleable) it.next();
            child.setRecycleId(deletedEntity.getRecycleId()); //将子节点的删除原因和其父节点一致
            child.setDeleted(Recycle.TRUE);
            dao.update((IEntity) child);
        }
    }
}
